joe di castrohttp://joedicastro.com2010-09-07T00:00:00+02:00Optimizar imagénes para la web2010-09-07T00:00:00+02:00joe di castrohttp://joedicastro.com/optimizar-imagenes-para-la-web.html<p><strong>El peso</strong> (tamaño) <strong>de las imágenes de un sitio web es determinante para</strong> dos aspectos fundamentales: <strong>la velocidad de carga de las páginas y el consumo de ancho de banda.</strong></p> <p>La velocidad de carga de las páginas es un factor cada día más importante, tanto para el posicionamiento de la web, como para la experiencia del usuario, que cada vez es más impaciente. El consumo de ancho de banda también es un factor muy importante, en cuanto a que suele estar directamente relacionado con el coste económico del alojamiento del sitio.</p> <p>Y aunque generalmente los programas de retoque fotográfico más comunes incorporan ya opciones especiales para guardar imágenes para la web, no todos exprimen al máximo el potencial de eliminar información superflua de una imagen (bueno, el EXIF puede no serlo tanto, dependiendo del sitio) sin que se vea afectada la calidad de la misma.</p> <p><strong>Yahoo</strong>, en sus consejos para optimizar la velocidad de carga de un sitio web, <strong>"Yahoo Best Practices for Speeding Up Your Web Site"</strong>, recomienda una serie de pequeñas aplicaciones en su <a href="http://developer.yahoo.com/performance/rules.html#opt_images">apartado para optimizar las imágenes.</a></p> <p>Son una serie de ordenes de línea comandos que han de aplicarse a las imágenes, una por una, algo tedioso y poco optimo si nuestro sitio web tiene cientos o miles de imágenes.</p> <p><strong>Por eso he creado un script en Python,</strong> <em>img4web.py</em>, <strong>que automatiza todo el proceso y procesa todas las imágenes en formatos .png y .jpg que se encuentren en una carpeta.</strong> </p> <p>Es muy sencillo de utilizar y al final del proceso tendremos una nueva carpeta "<strong>processed</strong>" con todas las imágenes y un resumen del proceso como este:</p> <div class="codehilite"><pre>================================================================================ Summary ================================================================================ Original Processed Save .jpgs: ( 31) 2.12 MiB ( 31) 1.82 MiB 301.28 KiB .pngs: ( 10)489.46 KiB ( 10)368.93 KiB 120.53 KiB -------------------------------------------------------------------------------- Total: ( 41) 2.60 MiB ( 41) 2.19 MiB 421.81 KiB </pre></div> <p>El script, las revisiones del código y las instrucciones de como descargarlo y usarlo podéis encontrarlas en el repositorio que está alojado en <a href="http://github.com/joedicastro/img4web">github</a>.</p> <p>Funciona tanto en Linux como en Windows, no lo he probado en un Mac.</p> <p>El código del script, es el siguiente:</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: &lt;utf8&gt; -*-</span> <span class="sd">&quot;&quot;&quot;</span> <span class="sd"> img4web.py: optimize .jpg and .png images for the web</span> <span class="sd">&quot;&quot;&quot;</span> <span class="c">#===============================================================================</span> <span class="c"># This Script optimizes .jpg and .png images for the web.</span> <span class="c">#</span> <span class="c"># This follows the &quot;Yahoo Best Practices for Speeding Up Your Web Site&quot; about</span> <span class="c"># optimize images. </span> <span class="c"># http://developer.yahoo.com/performance/rules.html#opt_images</span> <span class="c"># </span> <span class="c"># Uses the program pngcrush and the command jpegtran of the libjpeg library</span> <span class="c"># </span> <span class="c"># pngcrush, http://pmt.sourceforge.net/pngcrush/</span> <span class="c"># libjpg, http://www.ijg.org/</span> <span class="c">#</span> <span class="c"># In Linux they are usually available in the most popular distribution </span> <span class="c"># repositories, e.g.: </span> <span class="c"># In debian, Ubuntu as these packages:</span> <span class="c"># pngcrush</span> <span class="c"># libjpeg-progs</span> <span class="c">#</span> <span class="c"># In Windows pngcrush can be downloaded at </span> <span class="c"># http://sourceforge.net/projects/pmt/files/pngcrush-executables/</span> <span class="c"># and libjpeg can be downloaded (as gnuwin32) at </span> <span class="c"># http://gnuwin32.sourceforge.net/downlinks/jpeg.php</span> <span class="c">#</span> <span class="c"># How it runs?</span> <span class="c">#</span> <span class="c"># Get a list of .jpg and .png images in the working directory (where script </span> <span class="c"># runs) and process all of them one by one. Store the processed images in a new</span> <span class="c"># subdirectory named &#39;processed&#39; (I know, I didn&#39;t killed myself worrying about </span> <span class="c"># the name)</span> <span class="c">#===============================================================================</span> <span class="c">#===============================================================================</span> <span class="c"># Copyright 2009 joe di castro &lt;joe@joedicastro.com&gt;</span> <span class="c"># </span> <span class="c"># This program is free software: you can redistribute it and/or modify</span> <span class="c"># it under the terms of the GNU General Public License as published by</span> <span class="c"># the Free Software Foundation, either version 3 of the License, or</span> <span class="c"># (at your option) any later version.</span> <span class="c">#</span> <span class="c"># This program is distributed in the hope that it will be useful,</span> <span class="c"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span> <span class="c"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span> <span class="c"># GNU General Public License for more details.</span> <span class="c">#</span> <span class="c"># You should have received a copy of the GNU General Public License</span> <span class="c"># along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</span> <span class="c">#</span> <span class="c">#===============================================================================</span> <span class="n">__author__</span> <span class="o">=</span> <span class="s">&quot;joe di castro - joe@joedicastro.com&quot;</span> <span class="n">__license__</span> <span class="o">=</span> <span class="s">&quot;GNU General Public License version 2&quot;</span> <span class="n">__date__</span> <span class="o">=</span> <span class="s">&quot;30/12/2010&quot;</span> <span class="n">__version__</span> <span class="o">=</span> <span class="s">&quot;0.4&quot;</span> <span class="k">try</span><span class="p">:</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">glob</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">platform</span> <span class="kn">import</span> <span class="nn">re</span> <span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">Popen</span><span class="p">,</span> <span class="n">PIPE</span><span class="p">,</span> <span class="n">call</span> <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span> <span class="c"># Checks the installation of the necessary python modules </span> <span class="k">print</span><span class="p">((</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">&quot;An error found importing one module:&quot;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()[</span><span class="mi">1</span><span class="p">]),</span> <span class="s">&quot;You need to install it&quot;</span><span class="p">,</span> <span class="s">&quot;Stopping...&quot;</span><span class="p">]))</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="k">def</span> <span class="nf">best_unit_size</span><span class="p">(</span><span class="n">bytes_size</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Get a size in bytes &amp; convert it to the best IEC prefix for readability.</span> <span class="sd"> Return a dictionary with three pair of keys/values:</span> <span class="sd"> &#39;s&#39; -- (float) Size of path converted to the best unit for easy read</span> <span class="sd"> &#39;u&#39; -- (str) The prefix (IEC) for s (from bytes(2^0) to YiB(2^80))</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">for</span> <span class="n">exp</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">90</span> <span class="p">,</span> <span class="mi">10</span><span class="p">):</span> <span class="n">bu_size</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">bytes_size</span><span class="p">)</span> <span class="o">/</span> <span class="nb">pow</span><span class="p">(</span><span class="mf">2.0</span><span class="p">,</span> <span class="n">exp</span><span class="p">)</span> <span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="n">bu_size</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span> <span class="o">**</span> <span class="mi">10</span><span class="p">:</span> <span class="n">unit</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span><span class="s">&#39;bytes&#39;</span><span class="p">,</span> <span class="mi">10</span><span class="p">:</span><span class="s">&#39;KiB&#39;</span><span class="p">,</span> <span class="mi">20</span><span class="p">:</span><span class="s">&#39;MiB&#39;</span><span class="p">,</span> <span class="mi">30</span><span class="p">:</span><span class="s">&#39;GiB&#39;</span><span class="p">,</span> <span class="mi">40</span><span class="p">:</span><span class="s">&#39;TiB&#39;</span><span class="p">,</span> <span class="mi">50</span><span class="p">:</span><span class="s">&#39;PiB&#39;</span><span class="p">,</span> <span class="mi">60</span><span class="p">:</span><span class="s">&#39;EiB&#39;</span><span class="p">,</span> <span class="mi">70</span><span class="p">:</span><span class="s">&#39;ZiB&#39;</span><span class="p">,</span> <span class="mi">80</span><span class="p">:</span><span class="s">&#39;YiB&#39;</span><span class="p">}[</span><span class="n">exp</span><span class="p">]</span> <span class="k">break</span> <span class="k">return</span> <span class="p">{</span><span class="s">&#39;s&#39;</span><span class="p">:</span><span class="n">bu_size</span><span class="p">,</span> <span class="s">&#39;u&#39;</span><span class="p">:</span><span class="n">unit</span><span class="p">}</span> <span class="k">def</span> <span class="nf">get_size</span><span class="p">(</span><span class="n">the_path</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Get size of a directory tree or a file in bytes.&quot;&quot;&quot;</span> <span class="n">path_size</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">path</span><span class="p">,</span> <span class="n">directories</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">the_path</span><span class="p">):</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span> <span class="n">path_size</span> <span class="o">+=</span> <span class="n">os</span><span class="o">.</span><span class="n">lstat</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">filename</span><span class="p">))</span><span class="o">.</span><span class="n">st_size</span> <span class="k">for</span> <span class="n">directory</span> <span class="ow">in</span> <span class="n">directories</span><span class="p">:</span> <span class="n">path_size</span> <span class="o">+=</span> <span class="n">os</span><span class="o">.</span><span class="n">lstat</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">directory</span><span class="p">))</span><span class="o">.</span><span class="n">st_size</span> <span class="n">path_size</span> <span class="o">+=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">the_path</span><span class="p">)</span> <span class="k">return</span> <span class="n">path_size</span> <span class="k">def</span> <span class="nf">check_execs_posix_win</span><span class="p">(</span><span class="o">*</span><span class="n">progs</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Check if the programs are installed.</span> <span class="sd"> Returns two values:</span> <span class="sd"> (dict) windows_paths - a dictionary of executables/paths (keys/values)</span> <span class="sd"> (boolean) is_windows - True it&#39;s a Windows OS, False it&#39;s a *nix OS</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="k">def</span> <span class="nf">not_found</span><span class="p">(</span><span class="n">app</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot; If executable is not installed, exit and report.&quot;&quot;&quot;</span> <span class="n">msg</span> <span class="o">=</span> <span class="s">&#39;The {0} program is necessary to run this script&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="n">windows_paths</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">is_windows</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">if</span> <span class="n">platform</span><span class="o">.</span><span class="n">system</span><span class="p">()</span> <span class="o">==</span> <span class="s">&#39;Windows&#39;</span> <span class="k">else</span> <span class="bp">False</span> <span class="c"># get all the drive unit letters if the OS is Windows</span> <span class="n">windows_drives</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="s">r&#39;(\w:)</span><span class="se">\\</span><span class="s">&#39;</span><span class="p">,</span> <span class="n">Popen</span><span class="p">(</span><span class="s">&#39;fsutil fsinfo drives&#39;</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">)</span><span class="o">.</span> <span class="n">communicate</span><span class="p">()[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">is_windows</span> <span class="k">else</span> <span class="bp">None</span> <span class="k">for</span> <span class="n">prog</span> <span class="ow">in</span> <span class="n">progs</span><span class="p">:</span> <span class="k">if</span> <span class="n">is_windows</span><span class="p">:</span> <span class="c"># Set all commands to search the executable in all drives</span> <span class="n">win_cmds</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;dir /B /S {0}\*{1}.exe&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">prog</span><span class="p">)</span> <span class="k">for</span> <span class="n">letter</span> <span class="ow">in</span> <span class="n">windows_drives</span><span class="p">]</span> <span class="c"># Get the first location (usually in C:) of the all founded where </span> <span class="c"># the executable exists</span> <span class="n">exe_paths</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">Popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span><span class="o">.</span><span class="n">communicate</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">cmd</span> <span class="ow">in</span> <span class="n">win_cmds</span><span class="p">]))</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="c"># Assign the path to the executable or report not found if empty</span> <span class="n">windows_paths</span><span class="p">[</span><span class="n">prog</span><span class="p">]</span> <span class="o">=</span> <span class="n">exe_paths</span> <span class="k">if</span> <span class="n">exe_paths</span> <span class="k">else</span> <span class="n">not_found</span><span class="p">(</span><span class="n">prog</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">Popen</span><span class="p">([</span><span class="n">prog</span><span class="p">,</span> <span class="s">&#39;--help&#39;</span><span class="p">],</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">PIPE</span><span class="p">)</span> <span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span> <span class="n">not_found</span><span class="p">(</span><span class="n">prog</span><span class="p">)</span> <span class="k">return</span> <span class="n">windows_paths</span><span class="p">,</span> <span class="n">is_windows</span> <span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">execs</span><span class="p">,</span> <span class="n">windows</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Main section.&quot;&quot;&quot;</span> <span class="c"># Check if exists the subdirectory for store the results, else create it</span> <span class="n">dest_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">(),</span> <span class="s">&#39;processed&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">dest_path</span><span class="p">):</span> <span class="n">os</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">dest_path</span><span class="p">)</span> <span class="c"># Get the list of all .png an .jpg images in the current folder by type</span> <span class="n">jpg</span><span class="p">,</span> <span class="n">png</span> <span class="o">=</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;*.jp[e|g]*&#39;</span><span class="p">),</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;*.png&#39;</span><span class="p">)</span> <span class="c"># Get the original size of the images in bytes by type</span> <span class="n">org_jpg_sz</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">((</span><span class="n">get_size</span><span class="p">(</span><span class="n">orig_jpg</span><span class="p">)</span> <span class="k">for</span> <span class="n">orig_jpg</span> <span class="ow">in</span> <span class="n">jpg</span><span class="p">))</span> <span class="n">org_png_sz</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">((</span><span class="n">get_size</span><span class="p">(</span><span class="n">orig_png</span><span class="p">)</span> <span class="k">for</span> <span class="n">orig_png</span> <span class="ow">in</span> <span class="n">png</span><span class="p">))</span> <span class="c"># Get the executable&#39;s names (and path for windows) of the needed programs </span> <span class="n">jpegtran</span> <span class="o">=</span> <span class="n">execs</span><span class="p">[</span><span class="s">&#39;jpegtran&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">windows</span> <span class="k">else</span> <span class="s">&#39;jpegtran&#39;</span> <span class="n">pngcrush</span> <span class="o">=</span> <span class="n">execs</span><span class="p">[</span><span class="s">&#39;pngcrush&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">windows</span> <span class="k">else</span> <span class="s">&#39;pngcrush&#39;</span> <span class="c"># Process all .jpg images</span> <span class="k">for</span> <span class="n">jpg_img</span> <span class="ow">in</span> <span class="n">jpg</span><span class="p">:</span> <span class="n">call</span><span class="p">([</span><span class="n">jpegtran</span><span class="p">,</span> <span class="s">&#39;-copy&#39;</span><span class="p">,</span> <span class="s">&#39;none&#39;</span><span class="p">,</span> <span class="s">&#39;-optimize&#39;</span><span class="p">,</span> <span class="s">&#39;-perfect&#39;</span><span class="p">,</span> <span class="s">&#39;-outfile&#39;</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dest_path</span><span class="p">,</span> <span class="n">jpg_img</span><span class="p">),</span> <span class="n">jpg_img</span><span class="p">])</span> <span class="c"># Process all .png images</span> <span class="k">for</span> <span class="n">png_img</span> <span class="ow">in</span> <span class="n">png</span><span class="p">:</span> <span class="n">call</span><span class="p">([</span><span class="n">pngcrush</span><span class="p">,</span> <span class="s">&#39;-rem&#39;</span><span class="p">,</span> <span class="s">&#39;alla&#39;</span><span class="p">,</span> <span class="s">&#39;-reduce&#39;</span><span class="p">,</span> <span class="s">&#39;-brute&#39;</span><span class="p">,</span> <span class="n">png_img</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dest_path</span><span class="p">,</span> <span class="n">png_img</span><span class="p">)])</span> <span class="c"># Get the size of the processed images in bytes by type</span> <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">dest_path</span><span class="p">)</span> <span class="n">prc_jpg</span> <span class="o">=</span> <span class="p">[</span><span class="n">j</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;*.jp[e|g]*&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">jpg</span><span class="p">]</span> <span class="n">prc_png</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;*.png&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">png</span><span class="p">]</span> <span class="n">prc_jpg_sz</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">((</span><span class="n">get_size</span><span class="p">(</span><span class="n">new_j</span><span class="p">)</span> <span class="k">for</span> <span class="n">new_j</span> <span class="ow">in</span> <span class="n">prc_jpg</span><span class="p">))</span> <span class="n">prc_png_sz</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">((</span><span class="n">get_size</span><span class="p">(</span><span class="n">new_p</span><span class="p">)</span> <span class="k">for</span> <span class="n">new_p</span> <span class="ow">in</span> <span class="n">prc_png</span><span class="p">))</span> <span class="c"># Get a human readable size</span> <span class="n">ojs</span><span class="p">,</span> <span class="n">ops</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">org_jpg_sz</span><span class="p">),</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">org_png_sz</span><span class="p">)</span> <span class="n">pjs</span><span class="p">,</span> <span class="n">pps</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">prc_jpg_sz</span><span class="p">),</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">prc_png_sz</span><span class="p">)</span> <span class="n">tot_org</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">org_jpg_sz</span> <span class="o">+</span> <span class="n">org_png_sz</span><span class="p">)</span> <span class="n">tot_prc</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">prc_jpg_sz</span> <span class="o">+</span> <span class="n">prc_png_sz</span><span class="p">)</span> <span class="n">sjs</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">org_jpg_sz</span> <span class="o">-</span> <span class="n">prc_jpg_sz</span><span class="p">)</span> <span class="n">sps</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">(</span><span class="n">org_png_sz</span> <span class="o">-</span> <span class="n">prc_png_sz</span><span class="p">)</span> <span class="n">tts</span> <span class="o">=</span> <span class="n">best_unit_size</span><span class="p">((</span><span class="n">org_jpg_sz</span> <span class="o">+</span> <span class="n">org_png_sz</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">prc_jpg_sz</span> <span class="o">+</span> <span class="n">prc_png_sz</span><span class="p">))</span> <span class="c"># print a little report </span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;{0}{1}{0}{2:^80}{0}{1}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">,</span> <span class="s">&#39;=&#39;</span> <span class="o">*</span> <span class="mi">80</span><span class="p">,</span> <span class="s">&#39;Summary&#39;</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39; Original Processed Save&#39;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;.jpgs: ({6:3}){0:&gt;6.2f} {1:8}({7:3}){2:&gt;6.2f} {3:8}{4:&gt;6.2f} {5}&#39;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="n">ojs</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">ojs</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="n">pjs</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">pjs</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="n">sjs</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">sjs</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="nb">len</span><span class="p">(</span><span class="n">jpg</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">prc_jpg</span><span class="p">)))</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;.pngs: ({6:3}){0:&gt;6.2f} {1:8}({7:3}){2:&gt;6.2f} {3:8}{4:&gt;6.2f} {5}&#39;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="n">ops</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">ops</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="n">pps</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">pps</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="n">sps</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">sps</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="nb">len</span><span class="p">(</span><span class="n">png</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">prc_png</span><span class="p">)))</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;-&#39;</span> <span class="o">*</span> <span class="mi">80</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;Total: ({6:3}){0:&gt;6.2f} {1:8}({7:3}){2:&gt;6.2f} {3:8}{4:&gt;6.2f} {5}&#39;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="n">tot_org</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">tot_org</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="n">tot_prc</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">tot_prc</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="n">tts</span><span class="p">[</span><span class="s">&#39;s&#39;</span><span class="p">],</span> <span class="n">tts</span><span class="p">[</span><span class="s">&#39;u&#39;</span><span class="p">],</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">jpg</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">png</span><span class="p">)),</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">prc_jpg</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">prc_png</span><span class="p">))))</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span> <span class="n">WIN_EXECS</span><span class="p">,</span> <span class="n">WIN_OS</span> <span class="o">=</span> <span class="n">check_execs_posix_win</span><span class="p">(</span><span class="s">&#39;jpegtran&#39;</span><span class="p">,</span> <span class="s">&#39;pngcrush&#39;</span><span class="p">)</span> <span class="n">main</span><span class="p">(</span><span class="n">WIN_EXECS</span><span class="p">,</span> <span class="n">WIN_OS</span><span class="p">)</span> </pre></div> <p>Para una versión actualizada del código ir a <a href="https://github.com/joedicastro/img4web/blob/master/src/img4web.py">el fichero fuente.</a></p>